<?php
declare(strict_types=1);

namespace Hyperfx\Utils;

use Hyperfx\Framework\Logger\Logx;

class EncryptRollUtil {

    /**
     * @var array $secrets [{"secret": "xxx", "version": 1}, {"secret": "xxx", "version": 2}]
     */
    private array $secrets;
    private array $mapSecrets;
    public function __construct(array $secrets) {
        $this->secrets = $secrets;
        foreach ($secrets as $secret) {
            $this->mapSecrets[$secret['version']] = $secret;
        }
    }

    private static function algorithm(array $data, string $salt): string|false {
        ksort($data);
        $text = '';
        foreach ($data as $k => $v) {
            $text .= sprintf('%s%s&', $k, $v);
        }
        return hash('sha256', "text=".$text."&salt=".$salt);
    }

    public function check(array $data, string $encrypted, int $encryptedVersion = 1): bool {
        if (!isset($this->mapSecrets[$encryptedVersion])) {
            Logx::get()->alert('this secret not found', [
                'x_group' => 'EncryptRoll',
                'encryptedVersion' => $encryptedVersion
            ]);
            return false;
        }

        $currentSecret = $this->mapSecrets[$encryptedVersion];
        $oldEncrypted = self::algorithm($data, $currentSecret['secret']);
        if ($oldEncrypted === false) {
            Logx::get()->alert('encrypt error', [
                'x_group' => 'EncryptRoll',
                "data" => $data,
                'encryptedVersion' => $encryptedVersion
            ]);
            return false;
        }

        if (0 === strcmp($oldEncrypted, $encrypted)) {
            return true;
        }

        return false;
    }

    public function generate(array $data): array|false {
        $latest = end($this->secrets);
        $newEncrypted = self::algorithm($data, $latest['secret']);
        if ($newEncrypted === false) {
            Logx::get()->alert('encrypt error', [
                'x_group' => 'EncryptRoll',
                "data" => $data,
                'encryptedVersion' => $latest['version']
            ]);
            return false;
        }
        return [$newEncrypted, (int) $latest['version']];
    }
}